//-----------------------------------------------------------------------------
// Filename: SIPCancelTransaction.cs
//
// Description: SIP Transaction created in response to a CANCEL request.
// 
// History:
// 14 Feb 2006	Aaron Clauson	Created.
//
// License: 
// This software is licensed under the BSD License http://www.opensource.org/licenses/bsd-license.php
//
// Copyright (c) 2006 Aaron Clauson (aaronc@blueface.ie), Blue Face Ltd, Dublin, Ireland (www.blueface.ie)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that 
// the following conditions are met:
//
// Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 
// Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following 
// disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of Blue Face Ltd. 
// nor the names of its contributors may be used to endorse or promote products derived from this software without specific 
// prior written permission. 
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 
// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 
// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
// POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------

using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Text.RegularExpressions;
using BlueFace.VoIP.Authentication;
using CN.VoIP.Net;
using CN.Sys;
using log4net;

#if UNITTEST
using NUnit.Framework;
#endif

namespace CN.VoIP.Net.SIP
{
	public class SIPCancelTransaction : SIPTransaction
	{
        public SIPCancelTransaction(SIPRequest sipRequest) : base(sipRequest)
        {
            TransactionType = SIPTransactionTypesEnum.NonInvite;
        }

        public override void GotRequest(IPEndPoint localEndPoint, IPEndPoint inEndPoint, SIPRequest sipRequest)
        {
            try
            {
                logger.Debug("CANCEL request recevied, attempting to locate and cancel transaction.");

                SIPTransaction matchingTransaction = GetTransaction(GetRequestTransactionId(SIPMethodsEnum.INVITE.ToString(), sipRequest.Header.Via.TopViaHeader.Branch));

                SIPResponse cancelResponse;

                if (matchingTransaction != null)
                {
                    cancelResponse = GetCancelResponse(sipRequest.Header, SIPResponseStatusCodesEnum.Ok);
                }
                else
                {
                    cancelResponse = GetCancelResponse(sipRequest.Header, SIPResponseStatusCodesEnum.CallLegTransactionDoesNotExist);
                }

                TransactionState = SIPTransactionStatesEnum.Completed;
                SendFinalResponse(cancelResponse);
                base.FireTransactionStateChangedEvent();

                matchingTransaction.Cancel();
            }
            catch (Exception excp)
            {
                logger.Error("Exception SIPCancelTransaction GotRequest. " + excp.Message);
            }
        }

        public override void GotResponse(IPEndPoint localEndPoint, IPEndPoint inEndPoint, SIPResponse sipResponse)
        {
            if (sipResponse.StatusCode < 200)
            {
                logger.Warn("A SIP CANCEL transaction received an unexpected SIP information response " + sipResponse.ReasonPhrase + ".");
            }
            else
            {
                TransactionState = SIPTransactionStatesEnum.Completed;
                base.FireTransactionStateChangedEvent();
            }
        }

        private SIPResponse GetCancelResponse(SIPHeader requestHeader, SIPResponseStatusCodesEnum sipResponseCode)
        {
            try
            {
                SIPResponse cancelResponse = new SIPResponse(sipResponseCode);

                cancelResponse.Header = new SIPHeader(requestHeader.From, requestHeader.To, requestHeader.CSeq, requestHeader.CallId);
                cancelResponse.Header.CSeqMethod = SIPMethodsEnum.CANCEL.ToString();
                cancelResponse.Header.Via = requestHeader.Via;
                cancelResponse.Header.MaxForwards = Int32.MinValue;

                return cancelResponse;
            }
            catch (Exception excp)
            {
                logger.Error("Exception GetCancelResponse. " + excp.Message);
                throw excp;
            }
        }
    }
}
